package com.excilys.capicsoubank.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang3.ObjectUtils;
import org.springframework.security.core.userdetails.UserDetails;

/**
 * POJO User.
 * 
 * @author Tiphaine Ruy
 * 
 */
@Entity
@Table(name = "USER")
public class User implements Serializable, UserDetails {

	private static final long serialVersionUID = -8590394562502276275L;
	private Integer userId;
	private String username;
	private String password;
	private String firstname;
	private String lastname;
	private List<Account> accounts = new ArrayList<Account>();
	private List<Role> authorities = new ArrayList<Role>();

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "user_id", unique = true, nullable = false)
	public Integer getUserId() {
		return this.userId;
	}

	public void setUserId(Integer userId) {
		this.userId = userId;
	}

	@Override
	@Column(name = "username", nullable = false, length = 45)
	public String getUsername() {
		return this.username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	@Column(name = "password", nullable = false, length = 45)
	public String getPassword() {
		return password;
	}

	@Column(name = "firstname", nullable = false, length = 45)
	public String getFirstname() {
		return this.firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	@Column(name = "lastname", nullable = false, length = 45)
	public String getLastname() {
		return this.lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.EAGER)
	@OrderBy("accountId")
	public List<Account> getAccounts() {
		return this.accounts;
	}

	public void setAccounts(List<Account> accounts) {
		this.accounts = accounts;
	}

	@Override
	public String toString() {
		return "User [userId=" + userId + ", username=" + username
				+ ", firstname=" + firstname + ", lastname=" + lastname + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((username == null) ? 0 : username.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;

		if (obj == null)
			return false;

		if (getClass() != obj.getClass())
			return false;

		User user = (User) obj;

		return ObjectUtils.equals(userId, user.getUserId());
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	@ManyToMany
	@JoinTable(name = "USER_AUTHORITIES", joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
	public List<Role> getAuthorities() {

		return authorities;
	}

	public void setAuthorities(List<Role> authorities) {
		this.authorities = authorities;
	}

	@Override
	@Transient
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	@Transient
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	@Transient
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	@Transient
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return true;
	}

	/**
	 * Builder de la classe User.
	 * 
	 * @author "Grégory Coutant"
	 * 
	 */
	public static class Builder {
		private final User user = new User();

		/**
		 * Builder de l'attribut userId.
		 * 
		 * @param userId
		 *            L'ID du user
		 * @return Le Builder
		 */
		public Builder userId(Integer userId) {
			user.userId = userId;
			return this;
		}

		/**
		 * Builder de l'attribut username.
		 * 
		 * @param username
		 *            Le username
		 * @return Le Builder
		 */
		public Builder username(String username) {
			user.username = username;
			return this;
		}

		/**
		 * Builder de l'attribut firstname.
		 * 
		 * @param firstname
		 *            Le prénom
		 * @return Le Builder
		 */
		public Builder firstname(String firstname) {
			user.firstname = firstname;
			return this;
		}

		/**
		 * Builder de l'attribut lastname.
		 * 
		 * @param lastname
		 *            Le nom de famille
		 * @return Le Builder
		 */
		public Builder lastname(String lastname) {
			user.lastname = lastname;
			return this;
		}

		/**
		 * Builder de l'attribut accounts.
		 * 
		 * @param accounts
		 *            La liste des comptes
		 * @return Le Builder
		 */
		public Builder accounts(List<Account> accounts) {
			user.accounts = accounts;
			return this;
		}

		/**
		 * Builder de l'attribut password.
		 * 
		 * @param password
		 *            Le mot de passe
		 * @return Le Builder
		 */
		public Builder password(String password) {
			user.password = password;
			return this;
		}

		/**
		 * Construit le User.
		 * 
		 * @return Le User
		 */
		public User build() {
			return user;
		}
	}
}
